/*******************************************************************************
 * Copyright 2011 See AUTHORS file.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ******************************************************************************/

package com.goldsprite.infinityworld.screens.examples.entity;

import com.badlogic.gdx.*;
import com.badlogic.gdx.graphics.*;
import com.badlogic.gdx.graphics.g2d.*;
import com.badlogic.gdx.maps.tiled.*;
import com.badlogic.gdx.scenes.scene2d.*;
import com.badlogic.gdx.scenes.scene2d.ui.*;
import java.util.*;

import com.badlogic.gdx.assets.AssetManager;
import com.badlogic.gdx.maps.MapLayers;
import com.badlogic.gdx.maps.tiled.TiledMapTileLayer.Cell;
import com.badlogic.gdx.maps.tiled.renderers.OrthogonalTiledMapRenderer;
import com.badlogic.gdx.maps.tiled.tiles.StaticTiledMapTile;
import com.badlogic.gdx.utils.Align;
import com.goldsprite.gdxcore.logs.LogViewerService;
import com.goldsprite.gdxcore.screens.GScreen;
import com.goldsprite.gdxcore.utils.OrthoCamController;
import com.goldsprite.infinityworld.assets.GlobalAssets;
import com.goldsprite.infinityworld.entities.randommap.BlockId;
import com.goldsprite.simplexnoise.SimplexNoise2D;

public class TiledMapBench extends GScreen {

	private TiledMap map;
	private TiledMapRenderer renderer;
	private OrthographicCamera camera;
	private OrthoCamController cameraController;
	private AssetManager assetManager;
	private Texture tiles;
	private Texture texture;
	private BitmapFont font;
	private SpriteBatch batch;
	private LogViewerService logViewer;
	private Stage uiStage;

	private boolean crash;

	private boolean[] isUIEvent = {false};


	@Override
	public void create () {
		float w = getViewSize().x;
		float h = getViewSize().y;

		camera = new OrthographicCamera();
		camera.setToOrtho(false, (w / h) * 320, 320);
		camera.update();

		font = new BitmapFont();
		batch = new SpriteBatch();

		Skin skin = new Skin(Gdx.files.internal(GlobalAssets.skinPath));
		uiStage = new Stage(getViewport());

		//日志
		{
			//日志查看器
			logViewer = new LogViewerService(skin, 50, getViewSize().y-50, "Window");
			uiStage.addActor(logViewer.getRootLayout());
			LogViewerService.log("视口: "+getViewSize());
		}

		cameraController = new OrthoCamController(camera, isUIEvent);

		//世界
		{
			Texture tiles = new Texture(Gdx.files.internal(BlockId.cellTexturesPath));
			TextureRegion[][] splitTiles = TextureRegion.split(tiles, BlockId.regionSplit, BlockId.regionSplit);

			map = new TiledMap();
			MapLayers layers = map.getLayers();

			for (int l = 0; l < 2; l++) {
				TiledMapTileLayer layer = new TiledMapTileLayer(150, 100, BlockId.regionSplit, BlockId.regionSplit);

				for (int x = 0; x < 150; x++) {
					for (int y = 0; y < 100; y++) {
						//随机id
						BlockId blockId = getRanBlock(x, y, l);
						TextureRegion region = splitTiles[blockId.y][blockId.x];
						Cell cell = new Cell();
						cell.setTile(new StaticTiledMapTile(region));
						layer.setCell(x, y, cell);
					}
				}

				layers.add(layer);
			}
			LogViewerService.log("map: "+map);
			LogViewerService.log("layers: "+layers+"count: "+layers.size());
		}

		//渲染器
		renderer = new OrthogonalTiledMapRenderer(map);

		//输入
		InputMultiplexer imp = new InputMultiplexer();
		imp.addProcessor(cameraController);
		imp.addProcessor(uiStage);
		getImp().addProcessor(imp);

	}

	@Override
	public void render (float delta) {
		super.render(delta);
		try{
			if(!crash){
				//更新相机
				camera.update();
				//渲染器使用相机变换
				renderer.setView(camera);
				renderer.render();
			}
		}catch(Exception e){
			crash = true;
			LogViewerService.logError(e.getMessage()+": \n"+e.getCause());
		}
		//日志ui
		uiStage.act(delta);
		uiStage.draw();
	}


	private int minHigh = -64, maxHigh = 64;
	private BlockId getRanBlock(int x, int y, int type){
		double noise = SimplexNoise2D.getNorNoise(x, y, 0.02, 5, 0.45);
		/*ran *= 1.5f;
		ran = MathUtils.clamp(ran, 0, 1);
		BlockId blockId=BlockId.values()[(int) ((1-ran) * BlockId.values().length)];
		*/
		/*while(l==0 && blockId == BlockId.Air || (l==0 && blockId.blockType == 1)){
		 blockId = BlockId.values()[(int) (Math.random() * BlockId.values().length)];
		 }*/
		//if(blockId == BlockId.Air) blockId = BlockId.Grass;

		double height = mapNoiseToHeight(noise, minHigh, maxHigh);
		BlockId blockId = getBlockIdForHeight(height);

		//生成obj(树等)
		BlockId objId = BlockId.Air;
		//ran决定出现树的覆盖率
		float ran = new Random((long)(noise*1_000_000)).nextFloat();
		//草地树
		if(height>40+off){
			if(ran > 0.5f){
				if(ran < 0.65f) objId = BlockId.Tree;
				else objId = BlockId.Tree2;
			}
		}
		//沙滩树
		if(height>28+off+1 && height<34+off){
			if(ran > 0.8f)objId = BlockId.BeachTree;
		}

		return type == 0 ?blockId :objId;
	}

	////旧版代码
	public int off = -22;//越小目标高度面积越大
    // 高度映射表：每个高度范围对应一个BlockId
    public TreeMap<Integer, BlockId> heightMap = new TreeMap<Integer, BlockId>(){{
			//put(64+off, BlockId.Air);
			put(40+off, BlockId.Grass);
			put(38+off, BlockId.Grass2);
			put(34+off, BlockId.Sand);
			put(28+off, BlockId.Water);
			put(24+off, BlockId.Water2);
			put(18+off, BlockId.Water3);
			put(10+off, BlockId.Water4);
		}};
    public TreeMap<Integer, BlockId> obj_heightMap = new TreeMap<Integer, BlockId>(){{
			//put(64+off, BlockId.Air);
			put(45+off, BlockId.Tree);
			put(40+off, BlockId.Air);
		}};

	// 将噪声值映射到指定的高度区间, 接收值区间: 0 ~ 1
    private double mapNoiseToHeight(double noiseValue, int minHeight, int maxHeight) {
        return minHeight + noiseValue * (maxHeight - minHeight);
    }

    // 根据高度值查找对应的BlockId
    private BlockId getBlockIdForHeight(double height) {
		Integer key = heightMap.ceilingKey((int) height);  // 向上对齐到最近的高度
		if (key == null) key = heightMap.lastKey();
		return heightMap.get(key);
	}


}
